package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"gitee.com/wanjimao/platform/services/common/codecov"
)

// Default values for our CLI options
const (
	defaultCoverReport = "coverage.csv"
	defaultCoverJSON   = "coverage.json"
	defaultRepoName    = "tata-ol/services/"
	defaultSheetID     = "1gjAS7EIxD4PIgxq1KbzjSPC84bwlysnsBiy10vxEPqs"
	defaultSheetPush   = false
)

func main() {
	var coverFile string

	rootCmd := &cobra.Command{
		Use:   "codecov_cli",
		Short: "Code Coverage CLI",
	}
	{
		completeCoverProfile := &cobra.Command{
			Use:   "completeCoverProfile",
			Short: "Add untested packages to the provided coverprofile",
			Long: "completeCoverProfile adds information to the provided coverprofile generated by `go test` " +
				"to provide a more complete coverage profile, including untested packages.",
			Run: func(cmd *cobra.Command, args []string) {
				if err := codecov.CompleteCoverageFile(coverFile); err != nil {
					log.Fatal(err)
				}
			},
		}
		// Command Flags
		{
			completeCoverProfile.PersistentFlags().StringVar(
				&coverFile,
				"coverFile",
				"",
				"path of cover profile to be supplied",
			)
		}
		rootCmd.AddCommand(completeCoverProfile)
	}

	{
		var csvFile string
		var repoName string
		var sheetID string
		var pushToSheet bool
		testPriority := &cobra.Command{
			Use:   "testPriority",
			Short: "Create a test priority report in CSV format from a coverprofile converted to JSON",
			Long: "testPriority loads the provided coverprofile converted to JSON by `gocov convert`, " +
				"creating a CSV report of untested lines of code by package from greatest to least. " +
				"completeCoverProfile should be used before converting it to JSON to use with this command.",
			Run: func(cmd *cobra.Command, args []string) {
				if coverage, err := codecov.LoadFromFile(coverFile); err != nil {
					log.Fatal(err)
				} else if err := coverage.TestPriority(csvFile); err != nil {
					log.Fatal(err)
				}
				if repoName != "" {
					if err := removeRepoName(csvFile, repoName); err != nil {
						log.Fatal(err)
					}
				}
				if pushToSheet {
					var credentials string
					var found bool
					if credentials, found = os.LookupEnv("GOOGLE_SHEETS_CREDENTIALS"); !found {
						log.Println("There are no base64-encoded credentials set by the env var " +
							"GOOGLE_SHEETS_CREDENTIALS - did you mean to set them?")
					} else {
						fmt.Println("Using credentials pulled from GOOGLE_SHEETS_CREDENTIALS:", credentials)
						if err := codecov.UpdateDrive(sheetID, csvFile, credentials); err != nil {
							log.Fatal(err)
						}
					}
				}
			},
		}
		// Command Flags
		{
			testPriority.PersistentFlags().StringVar(
				&coverFile,
				"coverFile",
				defaultCoverJSON,
				"path of cover profile converted to JSON to be supplied",
			)
		}
		{
			testPriority.PersistentFlags().StringVar(
				&csvFile,
				"csvReport",
				defaultCoverReport,
				"path of where the CSV file should be generated",
			)
		}
		{
			testPriority.PersistentFlags().StringVar(
				&repoName,
				"repoName",
				defaultRepoName,
				"name of the repo to be removed from the CSV report;"+
					"Example: 'tata-ol/services/common/codecov becomes 'common/codecov'",
			)
		}
		{
			testPriority.PersistentFlags().StringVar(
				&sheetID,
				"sheetID",
				defaultSheetID,
				"Google Sheet ID to update;"+
					" Example: sheetID in 'docs.google.com/spreadsheets/d/sheetID/'",
			)
		}
		{
			testPriority.PersistentFlags().BoolVar(
				&pushToSheet,
				"pushToSheet",
				defaultSheetPush,
				"Whether or not to push to Google Sheets - set to true to push",
			)
		}
		rootCmd.AddCommand(testPriority)
	}

	{
		var credentialsToEncode string
		encodeCreds := &cobra.Command{
			Use:   "encodeCreds",
			Short: "Encode Google Sheets credentials to base64 for use with testPriority",
			Long: "encodeCreds takes a provided JSON file and encodes its contents to a base64 string, " +
				"creating a CSV report of untested lines of code by package from greatest to least. " +
				"completeCoverProfile should be used before converting it to JSON to use with this command.",
			Run: func(cmd *cobra.Command, args []string) {
				if creds, err := codecov.EncodeCredentials(credentialsToEncode); err != nil {
					log.Fatal(err)
				} else {
					fmt.Println("Encoded Credentials:")
					fmt.Println(creds)
					fmt.Println("Please set the GOOGLE_SHEETS_CREDENTIALS env var to the above string.")
				}
			},
		}
		{
			encodeCreds.PersistentFlags().StringVar(
				&credentialsToEncode,
				"creds",
				"",
				"path of credentials to encode into base64",
			)
		}
		rootCmd.AddCommand(encodeCreds)
	}

	if err := rootCmd.Execute(); err != nil {
		log.Fatal(err)
	}
}

// removeRepoName removes the repo name from the resulting coverage report
// for easier sorting when importing into Google Sheets.
func removeRepoName(csvPath string, repoName string) error {
	if read, err := ioutil.ReadFile(csvPath); err != nil {
		return err
	} else {
		newContents := strings.Replace(string(read), repoName, "", -1)
		if err = ioutil.WriteFile(csvPath, []byte(newContents), 0); err != nil {
			return err
		}
	}
	return nil
}
